<template>
    <div class="formula-editor">
        <div class="factor-pool">
            <div class="newCon clearfix">
                <span class="titName">
                    <svg-icon class="titIcon" name="index-project" width="18px" height="18px"
                        color=var(--el-text-color-primary)></svg-icon> &nbsp;
                    公式名称</span>
            </div>
            <div style="margin-bottom: 15px;">
                <el-input v-model="formulaName" placeholder="请输入公式名称" clearable style="width: 400px;"></el-input>
            </div>
            <div class="newCon clearfix">
                <span class="titName pull-left">
                    <svg-icon class="titIcon" name="index-project" width="18px" height="18px"
                        color=var(--el-text-color-primary)></svg-icon> &nbsp;
                    选择参数</span>
            </div>
            <ul class="factor-list">
                <li class="factor-item" v-for="(item, index) in factors" :key="index">
                    <span :class="['yzText', { 'text-primary': item.logic != null }]" @click="addFactor(item)"
                        :title="item">{{ item }}</span>
                </li>
            </ul>
        </div>
        <div ref="editorRef" class="editor-container">
            <div class="newCon clearfix">
                <span class="titName pull-left">
                    <svg-icon class="titIcon" name="index-fx" width="18px" height="18px"
                        color=var(--el-text-color-primary)></svg-icon> &nbsp;
                    公式配置</span>
                <div class="pull-right">
                    <el-button type="primary" plain @click="resetFormula">
                        <el-icon class="el-icon--left">
                            <Refresh />
                        </el-icon>重置
                    </el-button>
                </div>
            </div>
            <div class="editor-box">
                <div class="operator-box clearfix">
                    <ul class="pull-left" v-if="codeModel === 1" style="display: flex;">
                        <li v-for="(item, index) in operators" :key="index" class="operator-item"
                            @click="addOperator(item)">
                            <div
                                :style="{ fontSize: item.fontSize + 'px', height: item.height + 'px', fontWeight: item.fontWeight }">
                                {{ item.name }}</div>
                        </li>
                        <li class='number-input' @click="addNumber(functionContents.length)">
                            <svg-icon name="operate-numberInput" width="30px" height="30px"
                                color='var(--el-color-primary)' />
                        </li>
                    </ul>
                    <div class="code-toggle pull-right" @click="switchCodeModel">
                        <svg-icon class="titIcon" name="operate-code" width="26px" height="26px"
                            color=var(--el-text-color-primary)></svg-icon>
                    </div>
                </div>
                <div class="content-box" @dblclick="ContentDbClick" ref="contentBoxRef" v-if="codeModel === 1">
                    <!-- 位置指示器 -->
                    <div v-if="dragState.showPlaceholder" class="drop-placement-indicator" :style="{
                    left: `${dragState.placeholderPos.x}px`,
                    top: `${dragState.placeholderPos.y}px`,
                    width: `10px`,
                    height: `30px`
                }">
                        <div class="indicator-bar"></div>
                    </div>
                    <div v-for="(item, index) in functionContents" :index="index" :key="item.id"
                        class="draggable-navbar"
                        :class="{ 'is-dragging': item.isDragging, 'is-selected': selectIndex === index }"
                        :data-index="index" :style="{
                    transform: `translate(${item.offsetX}px, ${item.offsetY}px)`,
                    position: 'relative',
                    zIndex: item.isDragging ? 100 : 1
                }" @mousedown.left="handleElementClick(index, $event)">
                        <div :class="['content-item', 'content-item-factor']" v-if="item.type === 'factor'">{{ item.name
                            }}</div>
                        <div :class="['content-item', 'content-item-operator']" v-if="item.type === 'operator'">
                            <div
                                :style="{ fontSize: item.fontSize + 'px', height: item.height + 'px', fontWeight: item.fontWeight }">
                                {{ item.name }}</div>
                        </div>
                        <input :class="['content-item', 'content-item-number']" v-if="item.type === 'number'"
                            :data-id="item.id" v-model="item.name" :size="Math.max(item.name.length - 1, 1)"
                            @input="handleNumberInput(index, $event)" @dblclick="handleNumberItem(index, $event)"
                            :readonly="!item.isContenteditable" @blur="handleBlur(index)"></input>
                    </div>
                </div>
                <!-- <textarea v-if="codeModel===2" class="content-code" v-model="strContents" style="resize: none;"></textarea> -->
                 
                <div v-if="codeModel === 2" class="content-code" contenteditable @input="updateStrContents"
                    ref="editableDiv" @keyup="saveCursorPosition" @mouseup="saveCursorPosition">
                </div>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { convertChineseSymbols } from '@/utils/convertChineseSymbols';
import { Refresh  } from '@element-plus/icons-vue';
import { debounce } from 'lodash';
import { throttle } from 'lodash-es';
// import { convertChineseSymbols } from '../../utils/convertChineseSymbols';
// 类型定义
interface Factor {
    id: string | number
    name: string
}
interface Props {
    formInfo: any,
    operators?: any[],
}

const props = withDefaults(defineProps<Props>(), {
    operators: () => [
        { name: '+', fontSize: '24', height: '24', fontWeight: 500 },
        { name: '-', fontSize: '24', height: '24', fontWeight: 500 },
        { name: '*', fontSize: '20', height: '16', fontWeight: 500 },
        { name: '/', fontSize: '18', height: '18', fontWeight: 600 },
        { name: '(', fontSize: '18', height: '18', fontWeight: 600 },
        { name: ')', fontSize: '18', height: '18', fontWeight: 600 },
    ]
})
let selectIndex = ref<number>(-1);
const functionContents = ref<any[]>([]);
let elementKey = 0;
const addFactor = (item: Factor, index?: number) => {
    if (codeModel.value == 2) {
        ElMessage.error('当前为文本模式, 请切换到组件模式！');
        return
    }
    elementKey++;
    const newItem = {
        id: 'factor-' + elementKey,
        name: item,
        type: 'factor',
        isContenteditable: false
    }
    if (index !== undefined && index < functionContents.value.length) {
        functionContents.value.splice(index, 0, newItem);
    } else {
        functionContents.value.push(newItem);
    }
}
const addOperator = (item: any, index?: number) => {
    if (codeModel.value == 2) {
        ElMessage.error('当前为文本模式, 请切换到组件模式！');
        return
    }
    elementKey++;
    const newItem = {
        id: 'operator-' + elementKey,
        name: item.name,
        type: 'operator',
        fontSize: item.fontSize,
        height: item.height,
        fontWeight: item.fontWeight,
        isContenteditable: false
    }
    if (index !== undefined && index < functionContents.value.length) {
        functionContents.value.splice(index, 0, newItem);
    } else {
        functionContents.value.push(newItem);
    }
}
const addNumber = async (index: number) => {
    if (codeModel.value == 2) {
        ElMessage.error('当前为文本模式, 请切换到组件模式！');
        return
    }
    elementKey++;
    const newId = 'number-' + elementKey;
    const newItem = {
        id: newId,
        name: '',
        type: 'number',
        isContenteditable: true
    };

    if (index !== undefined && index < functionContents.value.length) {
        functionContents.value.splice(index, 0, newItem);
    } else {
        functionContents.value.push(newItem);
    }
    selectIndex.value = index;
    nextTick(() => {
        const target = contentBoxRef.value?.querySelector(`[data-id="${newId}"]`) as HTMLElement;
        if (target) {
            requestAnimationFrame(() => { target.focus(); });
        }
    })
}
const contentBoxRef = ref<HTMLElement | null>(null);
const ContentDbClick = (e: MouseEvent) => {
    const contentBox = contentBoxRef.value;
    if (!contentBox) return;

    // 检查点击目标是否是 content-box 自身（而不是子元素）
    // 精确判断是否点击在空白区域
    const isClickOnEmptyArea =
        e.target === contentBox ||
        (e.target as HTMLElement).classList.contains('content-box');

    if (!isClickOnEmptyArea) return;

    //把可编辑全部改为false
    functionContents.value.forEach((item) => {
        item.isContenteditable = false;
    })

    // 获取所有子元素的边界矩形
    const children = Array.from(contentBox.children);
    const rects = children.map(child => child.getBoundingClientRect());

    // 计算鼠标点击位置相对于contentBox的位置
    const boxRect = contentBox.getBoundingClientRect();
    const clickX = e.clientX - boxRect.left;
    const clickY = e.clientY - boxRect.top;

    // 找出点击位置最近的组件索引
    let insertIndex = functionContents.value.length;
    let minDistance = Infinity;

    rects.forEach((rect, index) => {
        const row = Math.abs(Math.floor((rect.top - boxRect.top + 30)) / 40);
        if (clickY >= 5 + (row - 1) * 40 && clickY < 5 + row * 40) {
            const centerX = rect.left - boxRect.left + rect.width / 2;
            const distance = Math.sqrt(Math.pow(clickX - centerX, 2));
            if (distance < minDistance) {
                minDistance = distance;
                // 如果点击位置在元素左侧，则插入到该元素前面
                insertIndex = clickX < centerX ? index : index + 1;
            }
        }
    });

    // 添加新数字输入框
    addNumber(insertIndex);
};

//自定义输入框
const handleNumberItem = (index: number, event: Event) => {
    //改为可编辑框
    functionContents.value.forEach((item, itemIndex) => {
        if (itemIndex === index) {
            item.isContenteditable = true;
        } else {
            item.isContenteditable = false;
        }
    })
    const target = event.target as HTMLElement;
    nextTick(() => {
        target.focus();
    })
}
const handleBlur = (index: number) => {
    if (!functionContents.value[index]) return;
    functionContents.value[index].isContenteditable = false;
    if (functionContents.value[index].name == null || functionContents.value[index].name == '') {
        functionContents.value.splice(index, 1);
        selectIndex.value = -1;
    }
}
const handleNumberInput = (index: number, _event: Event) => {
    // const target = event.target as any;
    // 清理非数字字符（如果需要纯数字输入）
    const cleanedText = functionContents.value[index].name.replace(/[^\d.-]/g, '');
    functionContents.value[index].name = cleanedText;
    // target.size = Math.max(target.value.length - 1, 1);
};
//拖拽功能
// 拖拽状态
const dragState = ref({
    isDragging: false,
    currentIndex: -1,
    startX: 0,
    startY: 0,
    initialOffsetX: 0,
    initialOffsetY: 0,
    showPlaceholder: false,
    placeholderPos: { x: 0, y: 0 }
});
//缓存变了，避免重复计算
let children: any;
let boxRect: any;
let boxLeft: any;
let boxRight: any;
// let firstRect: any;
// let lastRect: any;

let isClick = true; // 默认是点击
let startX: any, startY: any;
const handleElementClick = (index: number, e: MouseEvent) => {
    selectIndex.value = index;
    if (functionContents.value[index].isContenteditable) return;
    isClick = true;
    startX = e.clientX;
    startY = e.clientY;
    const target = e.currentTarget as HTMLElement;
    // 设置一个小的移动阈值（如 5px）
    // 定义移动处理函数
    const handleMove = throttle((moveEvent: MouseEvent) => {
        const dx = Math.abs(moveEvent.clientX - startX);
        const dy = Math.abs(moveEvent.clientY - startY);

        if (dx > 5 || dy > 5) {
            isClick = false; // 超过阈值，判定为拖拽
            startDrag(index, target, startX, startY); // 进入拖拽逻辑
            document.removeEventListener('mousemove', handleMove);
        }
    }, 16);

    // 添加移动事件监听
    document.addEventListener('mousemove', handleMove);

    // 添加鼠标释放事件监听
    const handleMouseUp = () => {
        if (isClick) {
            // 执行点击逻辑
            // selectIndex.value = index;
            //把可编辑全部改为false
            functionContents.value.forEach((item) => {
                item.isContenteditable = false;
            })
        }
        document.removeEventListener('mousemove', handleMove);
        document.removeEventListener('mouseup', handleMouseUp);
    };

    document.addEventListener('mouseup', handleMouseUp);
    e.preventDefault();
}
const startDrag = (index: number, target: HTMLElement, startX: number, startY: number) => {
    const contentBox = contentBoxRef.value;
    if (!contentBox) return;
    functionContents.value.forEach((item) => {
        item.isContenteditable = false;
    })

    children = Array.from(contentBox.children)
        .filter(el => !el.classList.contains('drop-placement-indicator'));
    // 获取content-box的边界
    boxRect = contentBox.getBoundingClientRect();
    boxLeft = boxRect.left;
    boxRight = boxRect.right;
    // firstRect = children[0].getBoundingClientRect();
    // lastRect = children[children.length - 1].getBoundingClientRect();



    const item = functionContents.value[index];
    if (item.type === 'number' && item.isContenteditable) return;

    const rect = target.getBoundingClientRect();

    dragState.value = {
        isDragging: true,
        currentIndex: index,
        startX: startX,
        startY: startY,
        initialOffsetX: item.offsetX || 0,
        initialOffsetY: item.offsetY || 0,
        showPlaceholder: false,
        placeholderPos: {
            x: rect.left,
            y: rect.top
        }
    };

    // 激活当前拖拽项
    functionContents.value.forEach((item, i) => {
        item.isActive = i === index;
        item.isDragging = i === index;
    });

    document.addEventListener('mousemove', handleDrag);
    document.addEventListener('mouseup', stopDrag);
};
// 使用requestAnimationFrame优化拖拽性能
let animationFrameId: number | null = null;

const handleDrag = throttle((e: MouseEvent) => {
    if (!dragState.value.isDragging) return;
    if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
    }
    animationFrameId = requestAnimationFrame(() => {
        const { currentIndex, startX, startY, initialOffsetX, initialOffsetY } = dragState.value;
        const dx = e.clientX - startX;
        const dy = e.clientY - startY;

        functionContents.value[currentIndex].offsetX = initialOffsetX + dx;
        functionContents.value[currentIndex].offsetY = initialOffsetY + dy;

        // 计算并显示放置位置指示器
        updatePlaceholderPosition(currentIndex, e.clientX, e.clientY);
    });
}, 16);

let targetIndex = -1;
const updatePlaceholderPosition = (draggedIndex: number, mouseX: number, mouseY: number) => {


    let closestIndex = -1;
    let minDistance = Infinity;
    // let insertBefore = false;


    children.forEach((child: any, index: number) => {
        if (index === draggedIndex) return;

        const rect = child.getBoundingClientRect();
        const centerX = rect.left + rect.width / 2;
        const centerY = rect.top + rect.height / 2;

        // 计算带权重的距离（Y轴权重加倍）
        const yWeight = 3; // Y轴权重系数，可根据需要调整
        const dx = Math.max(boxLeft, Math.min(mouseX, boxRight)) - centerX;
        const dy = (mouseY - centerY) * yWeight; // Y轴距离乘权重

        const distance = Math.sqrt(dx * dx + dy * dy);

        if (distance < minDistance) {
            minDistance = distance;
            closestIndex = index;
            // insertBefore = mouseX < centerX;
        }
    });

    // 位置处理
    if (closestIndex !== -1) {
        const targetRect = children[closestIndex].getBoundingClientRect();
        const childLeft = targetRect.left - boxRect.left;
        const childRight = targetRect.right - boxRect.left;

        // 更精确的指示器位置计算
        if (mouseX < targetRect.left + 15) {
            // 指示器在元素左侧
            dragState.value.placeholderPos = {
                x: childLeft - 10,
                y: targetRect.top - boxRect.top,
            };
            targetIndex = closestIndex;
        } else if (mouseX > targetRect.right - 15) {
            // 指示器在元素右侧
            dragState.value.placeholderPos = {
                x: childRight,
                y: targetRect.top - boxRect.top,
            };
            targetIndex = closestIndex + 1;
        }
        dragState.value.showPlaceholder = true;
    } else {
        dragState.value.showPlaceholder = false;
    }
};

const stopDrag = () => {
    if (!dragState.value.isDragging) return;

    if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
        animationFrameId = null;
    }

    const { currentIndex } = dragState.value;
    const draggedItem = functionContents.value[currentIndex];

    // 执行实际的位置交换
    performPositionSwap(currentIndex);

    // 重置状态
    draggedItem.offsetX = 0;
    draggedItem.offsetY = 0;
    draggedItem.isDragging = false;
    dragState.value.isDragging = false;
    dragState.value.showPlaceholder = false;

    document.removeEventListener('mousemove', handleDrag);
    document.removeEventListener('mouseup', stopDrag);
};

const performPositionSwap = (draggedIndex: number) => {
    if (!dragState.value.showPlaceholder) return;

    const contentBox = contentBoxRef.value;
    if (!contentBox) return;

    // 确保目标索引有效
    if (targetIndex === -1 || draggedIndex === targetIndex) return;

    // 执行数组元素移动
    const item = functionContents.value.splice(draggedIndex, 1)[0];

    // 调整目标索引，因为我们已经移除了一个元素
    const adjustedTargetIndex = targetIndex > draggedIndex ? targetIndex - 1 : targetIndex;

    functionContents.value.splice(adjustedTargetIndex, 0, item);
    selectIndex.value = adjustedTargetIndex;
};
//增加删除功能
const delElement = (e: KeyboardEvent) => {
    // 检查是否按下了Del或Backspace键
    if ((e.key === 'Delete' || e.key === 'Backspace') && selectIndex.value >= 0 && !functionContents.value[selectIndex.value].isContenteditable) {
        functionContents.value.splice(selectIndex.value, 1);
        selectIndex.value = -1;
    }
}
/**
 * 将数组对象转换为数学表达式字符串
 * @param items 公式项数组
 * @returns 数学表达式字符串
 */
const codeModel = ref<number>(1); //1|组件模式；2|文本模式
const strContents = ref<string>('');
const switchCodeModel = () => {
    if (codeModel.value === 1) {
        codeModel.value = 2;
        strContents.value = itemsToString(functionContents.value);
        nextTick(() => {
            if (editableDiv.value) {
                editableDiv.value.innerHTML = strContents.value.replace(/{(.*?)}/g, '<span style="color:var(--el-color-primary)">{$1}</span>');
            }
        })
    } else {
        codeModel.value = 1;
        functionContents.value = stringToItems(strContents.value);
    }
}
function itemsToString(items: any[]): string {
    let result = '';

    for (let i = 0; i < items.length; i++) {
        const item = items[i];

        // 处理不同类型的项
        switch (item.type) {
            case 'factor':
                result += `{${item.name}}`;
                break;
            case 'number':
                // 处理负数情况
                if (item.name.startsWith('-') && i > 0) {
                    const prevItem = items[i - 1];
                    // 如果前一个项是运算符(除了右括号)，则认为是负数
                    if (prevItem.type === 'operator' && prevItem.name !== ')') {
                        result += item.name;
                    } else {
                        // 否则认为是减号加正数
                        result += `-${item.name.substring(1)}`;
                    }
                } else {
                    result += item.name;
                }
                break;
            case 'operator':
                result += item.name;
                break;
        }
    }

    return result;
}

/**
 * 将数学表达式字符串转换为数组对象
 * @param str 数学表达式字符串
 * @returns 公式项数组
 */
function stringToItems(str: string): any[] {
    const items: any[] = [];
    let rowId = 1;
    let i = 0;

    while (i < str.length) {
        const char = str[i];

        // 处理因子 {xxx}
        if (char === '{') {
            const endIndex = str.indexOf('}', i);
            if (endIndex === -1) throw new Error('Unclosed factor bracket');

            const factorName = str.substring(i + 1, endIndex);
            items.push({
                id: `factor-${rowId++}`,
                name: factorName,
                type: 'factor',
                isContenteditable: false
            });
            i = endIndex + 1;
        }
        // 处理数字(包括负数)
        else if (isDigit(char) || (char === '-' && isNextCharDigit(str, i))) {
            let numStr = char;
            i++;

            // 收集数字部分(包括小数点)
            while (i < str.length && (isDigit(str[i]) || str[i] === '.')) {
                numStr += str[i];
                i++;
            }

            // 处理科学计数法(如1e-3)
            if (i < str.length && str[i].toLowerCase() === 'e') {
                numStr += str[i];
                i++;
                if (i < str.length && (str[i] === '+' || str[i] === '-')) {
                    numStr += str[i];
                    i++;
                }
                while (i < str.length && isDigit(str[i])) {
                    numStr += str[i];
                    i++;
                }
            }

            items.push({
                id: `number-${rowId++}`,
                name: numStr,
                type: 'number',
                isContenteditable: false
            });
        }
        // 处理运算符
        else if (isOperator(char)) {
            // 特殊处理负号(当作为一元运算符时)
            if (char === '-' && (i === 0 || isOperator(str[i - 1]) || str[i - 1] === '(')) {
                // 负号后面跟着数字，则合并为负数
                if (i + 1 < str.length && isDigit(str[i + 1])) {
                    // 这里不处理，让数字处理逻辑捕获它
                    i++;
                    continue;
                }
            }

            items.push({
                id: `operator-${rowId++}`,
                name: char,
                type: 'operator',
                fontSize: getOperatorFontSize(char),
                height: getOperatorHeight(char),
                fontWeight: getOperatorFontWeight(char),
                isContenteditable: false
            });
            i++;
        }
        // 忽略空格
        else if (char === ' ') {
            i++;
        }
        else {
            throw new Error(`Unexpected character: ${char} at position ${i}`);
        }
    }

    return items;
}

// 辅助函数
function isDigit(char: string): boolean {
    return /[0-9]/.test(char);
}

function isOperator(char: string): boolean {
    return /[+\-*/()]/.test(char);
}

function isNextCharDigit(str: string, index: number): boolean {
    return index + 1 < str.length && isDigit(str[index + 1]);
}

function getOperatorFontSize(op: string): string {
    switch (op) {
        case '+': case '-': return '24';
        case '*': return '20';
        case '/': case '(': case ')': return '18';
        default: return '18';
    }
}

function getOperatorHeight(op: string): string {
    switch (op) {
        case '+': case '-': return '24';
        case '*': return '16';
        case '/': case '(': case ')': return '18';
        default: return '18';
    }
}

function getOperatorFontWeight(op: string): number {
    switch (op) {
        case '/': case '(': case ')': return 600;
        default: return 500;
    }
}

// 更新 strContents 的值（去除 HTML 标签）
const editableDiv = ref<HTMLDivElement | null>(null);
const lastCursorPos = ref(0);
const debouncedRender = debounce(() => {
    if (editableDiv.value) {
        editableDiv.value.innerHTML = strContents.value.replace(/{(.*?)}/g, '<span style="color:var(--el-color-primary)">{$1}</span>');
        restoreCursorPosition(lastCursorPos.value);
    }
}, 200);

const updateStrContents = (e: any) => {
    if (isComposing) return; // 拼音输入过程中不处理
    
    saveCursorPosition();
    const rawText = e.target.innerText;
    strContents.value = convertChineseSymbols(rawText);
    debouncedRender();
};

// 保存光标位置
const saveCursorPosition = () => {
    const sel = window.getSelection();
    if (sel && editableDiv.value && sel.rangeCount > 0) {
        const range = sel.getRangeAt(0);
        const preRange = range.cloneRange();
        preRange.selectNodeContents(editableDiv.value);
        preRange.setEnd(range.endContainer, range.endOffset);
        lastCursorPos.value = preRange.toString().length;
    }
};

// 恢复光标位置
const restoreCursorPosition = (pos: any) => {
    const sel = window.getSelection();
    if (sel) {
        sel.removeAllRanges();
        const range = document.createRange();
        let charCount = 0;
        let targetNode: any = null;

        const traverse = (node: any) => {
            if (node.nodeType === Node.TEXT_NODE) {
                const nextCount = charCount + node.length;
                if (charCount <= pos && nextCount >= pos) {
                    targetNode = node;
                    range.setStart(node, pos - charCount);
                    range.collapse(true);
                }
                charCount = nextCount;
            } else {
                Array.from(node.childNodes).forEach(child => {
                    if (!targetNode) traverse(child);
                });
            }
        };

        traverse(editableDiv.value);
        sel.addRange(range);
    }
};
const resetFormula = () => {
    if (codeModel.value === 1) {
        functionContents.value = [];
    } else if (codeModel.value === 2 && editableDiv.value) {
        editableDiv.value.innerHTML = '';
    }
}

const formula = ref('');
const factors = ref<any[]>([]);
const formulaName = ref('');
const getFormula = (newValue: any) => {
    codeModel.value = 1;
    try {
        functionContents.value = stringToItems(newValue || '');
    } catch (error) {
        console.error('公式解析失败:', error);
        // 提供默认值或清空内容
        functionContents.value = [];
        // ElMessage.error('公式包含非法字符，请检查后重试');
    }
}
const doInfo = () => {
    resetFormula();
    if (props.formInfo.editType == 2) {
        formulaName.value = props.formInfo.name;
        formula.value = props.formInfo.formula;
        getFormula(formula.value);
    } else {
        // 新增模式下的初始化
        formulaName.value = '';
        formula.value = '';
    }
    factors.value = props.formInfo.factors ? props.formInfo.factors.slice(0) : [];
};

watch(() => props.formInfo,
    (newValue) => {
        console.log('改变Form：', newValue);
        doInfo(); // 此时 doInfo 已定义
    }, { immediate: true }
);


const saveFormula = () => {
    let formula = codeModel.value === 1 ? itemsToString(functionContents.value) : strContents.value;
    return formula;
}
let isComposing = false;
onMounted(() => {
    // doInfo();
    document.addEventListener('keydown', delElement);
    editableDiv.value?.addEventListener('compositionstart', () => {
        isComposing = true;
    });
    editableDiv.value?.addEventListener('compositionend', () => {
        isComposing = false;
        // 手动触发一次更新
        updateStrContents({ target: editableDiv.value } as any);
    });
})
onUnmounted(() => {
    document.removeEventListener('keydown', delElement);
})

defineExpose({ saveFormula, formulaName });

</script>
<style lang="scss" scoped>
.formula-editor {
    color: var(--el-text-color-primary);
}

.newCon .titName {
    font-size: 14px;
    color: var(--el-text-color-primary);
    font-weight: bold;
    line-height: 28px;
    display: flex;
    align-items: center;
    padding-bottom: 10px;
}

.factor-list {
    padding-bottom: 10px;
}

.factor-item {
    display: inline-block;
    padding-right: 50px;
    border: 1px solid var(--el-color-primary-light-8);
    font-size: 12px;
    border-radius: 4px;
    position: relative;
    margin: 0 10px 10px 0;

    .yzText {
        cursor: pointer;
        padding: 10px;
        display: block;
    }

    .optPart {
        opacity: 0;
        position: absolute;
        right: 0;
        top: 0;
        width: 50px;
        background-color: var(--el-color-primary-light-9);
        height: 32px;
        border-radius: 0 4px 4px 0;
        font-size: 16px;
        display: flex;

        .el-icon {
            cursor: pointer;
            flex: 1;
            height: 100%;
            width: 50%;
            text-align: center;
        }
    }

    &:hover {
        background-color: var(--el-fill-color);
        border-color: var(--el-color-primary-light-3);
        color: var(--el-color-primary);

        .optPart {
            opacity: 1;
        }
    }
}

.editor-box {
    border: 1px solid var(--el-border-color);
    border-radius: 4px;
    overflow: hidden
}

.operator-box {
    border-bottom: 1px solid var(--el-border-color);
    height: 40px;
    padding: 5px 10px;
    background-color: color-mix(in srgb, var(--el-color-primary-light-9) 20%, var(--el-bg-color-overlay) 80%);
}

.operator-item {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 30px;
    width: 40px;
    font-family: cursive;
    border-radius: 4px;
    margin: 0 5px;
    user-select: none;
    cursor: pointer;

    &:hover {
        background-color: var(--el-fill-color);
    }
}

.number-input {
    display: flex;
    margin-left: 10px;
    cursor: pointer;
}

.content-box {
    min-height: 100px;
    padding: 10px;
    position: relative;
    display: flex;
    flex-wrap: wrap;
    cursor: col-resize;
    background-color: var(--el-fill-color-lighter);
}

.content-code {
    min-height: 100px;
    padding: 10px;
    width: 100%;
    border: none;
    font-family: serif;
    font-size: 16px;
    font-weight: 600;
    line-height: 25px;
    letter-spacing: 2px;
}

.content-item {
    display: inline-flex;
    align-items: center;
    height: 30px;
    border-radius: 5px;
}

.content-item-factor {
    padding: 10px;
    background-color: var(--el-color-primary-light-9);
    font-size: 12px;
    border: 1px solid var(--el-color-primary-light-8);
}

.content-item-operator {
    padding: 10px 5px;
    font-family: cursive;
    background-color: transparent;
    border: 1px dashed transparent;
}

.content-item-number {
    padding: 10px 8px;
    border: 1px dashed var(--el-border-color-light);
    min-width: 28px;
    user-select: none;
    -webkit-user-select: none;
    font-family: monospace;
    /* 使用等宽字体 */
    font-size: 14px;
    cursor: auto;
}

.draggable-navbar {
    margin: 0 10px 10px 0;
    height: 30px;
    border-radius: 4px;
    overflow: hidden;
    cursor: auto;
    // transition: transform 0.1s ease;
    user-select: none;

    &.is-dragging {
        cursor: move;
        opacity: 0.7;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
    }
}

.drop-placement-indicator {
    position: absolute;
    pointer-events: none;
    z-index: 99;
    // background-color: var(--el-color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    /* 使用transform的translate来确保像素对齐 */
    transform: translate(0, 0);
    will-change: transform;

    .indicator-bar {
        background-color: var(--el-color-primary);
        border-radius: 2px;
        width: 2px;
        height: 25px;
        /* 强制GPU渲染，可能改善渲染一致性 */
        backface-visibility: hidden;
        transform: translateZ(0);
        /* 确保边框清晰 */
        -webkit-pixel-aligned: true;
    }
}

.is-selected .content-item-factor {
    border: 1px dashed var(--el-color-primary);
}

.is-selected .content-item-operator {
    border-color: var(--el-color-primary);
}

.is-selected .content-item-number {
    border-color: var(--el-color-primary);
}

.code-toggle {
    display: flex;
    padding: 2px 10px;
    border-radius: 4px;

    &:hover {
        cursor: pointer;
        background-color: var(--el-fill-color);
    }
}
</style>
